package com.jungle.design.mode.service.impl.order;

import com.jungle.design.mode.annotation.Strategy;
import com.jungle.design.mode.service.IStrategyHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public abstract class AbstractStrategyContext<T, R> implements ApplicationContextAware {

   private Map<String, IStrategyHandler<T, R>> implMap = new ConcurrentHashMap<>();

   private final String DELIMITER = "####";

   /**
    * 获得bean 的class
    *
    * @param <K> 类型
    * @return
    */
   abstract <K> Class<K> getClazz();

   /**
    * 返回spring中的beanName
    *
    * @return
    */
   abstract String getBeanName();


   /**
    * 执行函数
    *
    * @param strategy 策略类型
    * @param module   模块
    * @param param    参数
    * @return
    */
   public R execute(String strategy, String module, T param) {

       String key = StringUtils.join(module, DELIMITER, strategy);
       IStrategyHandler<T, R> handler = implMap.get(key);
       log.debug("策略实现集合{}", implMap);
       if (handler == null) {
           throw new RuntimeException("没有相应的策略实现");
       }
       R apply = handler.apply(param);
       return apply;
   }


   @Override
   @SuppressWarnings("unchecked")
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
       log.error("AbstractStrategy 执行");

       Class<Object> clazz = getClazz();
       Object bean = applicationContext.getBean(getBeanName(), clazz);
       if (bean == null) {
           return;
       }
       Strategy strategyAnnotation = bean.getClass().getAnnotation(Strategy.class);
       if (strategyAnnotation == null) {
           log.error("类[{}]没有添加Strategy注解", clazz);
           return;
       }
       // 模块的名称
       String module = strategyAnnotation.module();
       Method[] declaredMethods = clazz.getDeclaredMethods();

       if (ArrayUtils.isEmpty(declaredMethods)) {
           throw new RuntimeException(clazz + "没有相关策略方法");
       }

       for (Method declaredMethod : declaredMethods) {
           Strategy annotation = declaredMethod.getAnnotation(Strategy.class);
           if (annotation == null) {
               continue;
           }
           try {
               // 用module和 四个 #### 加上 value 组成map的key
               String key = org.apache.commons.lang3.StringUtils.join(module, DELIMITER, annotation.value());
               IStrategyHandler<T, R> handler = (IStrategyHandler<T, R>) declaredMethod.invoke(bean);
               implMap.put(key, handler);
           } catch (IllegalAccessException | InvocationTargetException e) {
               log.error("模块[{}]策略处理发生了错误", module, e);
           }
       }
   }
}
